當一個行為需要經過多道步驟時,可以將步驟串在一起。
該模式常見於兩種情境:
以上兩個情境轉換到現實則是:
實踐的作法是:
將相關步驟串在一起的好處是,步驟變更時,只要更換步驟的下一步就好,不用動到太多程式碼。
以下範例以需求「權限的驗證,必須通過所有驗證才算通過」為核心製作。
徽章物件、使用者物件:Badge
、User
public class Badge {
private String name;
public Badge(String name) {
this.name = name;
}
public String show() {
return name;
}
}
public class Player {
private String name;
private HashMap<String, Badge> badgeBox = new HashMap<>();
public Player(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addNewBadge(Badge badge) {
badgeBox.put(badge.show(), badge);
}
public Badge showBadge(String badgeName) {
return badgeBox.get(badgeName);
}
}
步驟的虛擬層親代:Doorkeeper
public abstract class Doorkeeper {
protected String name;
protected Doorkeeper nextDoorkeeper;
protected Doorkeeper(String name) {
this.name = name;
}
public void setNextDoorkeeper(Doorkeeper doorkeeper) {
this.nextDoorkeeper = doorkeeper;
}
public abstract boolean check(Player player);
}
步驟子代:BoulderBadgeDoorkeeper
、CascadeBadgeDoorkeeper
、ThunderBadgeDoorkeeper
、RainbowBadgeDoorkeeper
、SoulBadgeDoorkeeper
、MarshBadgeDoorkeeper
、VolcanoBadgeDoorkeeper
、EarthBadgeDoorkeeper
(Chain of Responsibility 物件)
public class BoulderBadgeDoorkeeper extends Doorkeeper {
public BoulderBadgeDoorkeeper() {
super("灰色徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有灰色徽章");
Badge badge = player.showBadge("Boulder");
if (badge == null) {
System.out.println("你未持有灰色徽章,不能通過此門\n");
return false;
}
System.out.println("你持有灰色徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class CascadeBadgeDoorkeeper extends Doorkeeper {
public CascadeBadgeDoorkeeper() {
super("藍色徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有藍色徽章");
Badge badge = player.showBadge("Cascade");
if (badge == null) {
System.out.println("你未持有藍色徽章,不能通過此門\n");
return false;
}
System.out.println("你持有藍色徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class ThunderBadgeDoorkeeper extends Doorkeeper {
public ThunderBadgeDoorkeeper() {
super("橙色徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有橙色徽章");
Badge badge = player.showBadge("Thunder");
if (badge == null) {
System.out.println("你未持有橙色徽章,不能通過此門\n");
return false;
}
System.out.println("你持有橙色徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class RainbowBadgeDoorkeeper extends Doorkeeper {
public RainbowBadgeDoorkeeper() {
super("彩虹徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有彩虹徽章");
Badge badge = player.showBadge("Rainbow");
if (badge == null) {
System.out.println("你未持有彩虹徽章,不能通過此門\n");
return false;
}
System.out.println("你持有彩虹徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class SoulBadgeDoorkeeper extends Doorkeeper {
public SoulBadgeDoorkeeper() {
super("粉紅徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有粉紅徽章");
Badge badge = player.showBadge("Soul");
if (badge == null) {
System.out.println("你未持有粉紅徽章,不能通過此門\n");
return false;
}
System.out.println("你持有粉紅徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class MarshBadgeDoorkeeper extends Doorkeeper {
public MarshBadgeDoorkeeper() {
super("金色徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有金色徽章");
Badge badge = player.showBadge("Marsh");
if (badge == null) {
System.out.println("你未持有金色徽章,不能通過此門\n");
return false;
}
System.out.println("你持有金色徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class VolcanoBadgeDoorkeeper extends Doorkeeper {
public VolcanoBadgeDoorkeeper() {
super("深紅徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有深紅徽章");
Badge badge = player.showBadge("Volcano");
if (badge == null) {
System.out.println("你未持有深紅徽章,不能通過此門\n");
return false;
}
System.out.println("你持有深紅徽章,請通過此門\n");
return nextDoorkeeper.check(player);
}
}
public class EarthBadgeDoorkeeper extends Doorkeeper {
public EarthBadgeDoorkeeper() {
super("綠色徽章檢查者");
}
@Override
public boolean check(Player player) {
System.out.println("我是 " + name + ",負責檢查是否有綠色徽章");
Badge badge = player.showBadge("Earth");
if (badge == null) {
System.out.println("你未持有綠色徽章,不能通過此門");
return false;
}
System.out.println("你持有綠色徽章,請通過此門\n");
return true;
}
}
測試,挑戰者小智嘗試通過冠軍之路的徽章檢查:VictoryRoadChainOfResponsibilitySample
public class VictoryRoadChainOfResponsibilitySample {
public static void main(String[] args) {
Player player = new Player("小智");
player.addNewBadge(new Badge("Boulder"));
player.addNewBadge(new Badge("Cascade"));
player.addNewBadge(new Badge("Thunder"));
player.addNewBadge(new Badge("Rainbow"));
player.addNewBadge(new Badge("Soul"));
player.addNewBadge(new Badge("Marsh"));
player.addNewBadge(new Badge("Volcano"));
player.addNewBadge(new Badge("Earth"));
Doorkeeper boulderBadgeDoorkeeper = new BoulderBadgeDoorkeeper();
Doorkeeper cascadeBadgeDoorkeeper = new CascadeBadgeDoorkeeper();
Doorkeeper thunderBadgeDoorkeeper = new ThunderBadgeDoorkeeper();
Doorkeeper rainbowBadgeDoorkeeper = new RainbowBadgeDoorkeeper();
Doorkeeper soulBadgeDoorkeeper = new SoulBadgeDoorkeeper();
Doorkeeper marshBadgeDoorkeeper = new MarshBadgeDoorkeeper();
Doorkeeper volcanoBadgeDoorkeeper = new VolcanoBadgeDoorkeeper();
Doorkeeper earthBadgeDoorkeeper = new EarthBadgeDoorkeeper();
boulderBadgeDoorkeeper.setNextDoorkeeper(cascadeBadgeDoorkeeper);
cascadeBadgeDoorkeeper.setNextDoorkeeper(thunderBadgeDoorkeeper);
thunderBadgeDoorkeeper.setNextDoorkeeper(rainbowBadgeDoorkeeper);
rainbowBadgeDoorkeeper.setNextDoorkeeper(soulBadgeDoorkeeper);
soulBadgeDoorkeeper.setNextDoorkeeper(marshBadgeDoorkeeper);
marshBadgeDoorkeeper.setNextDoorkeeper(volcanoBadgeDoorkeeper);
volcanoBadgeDoorkeeper.setNextDoorkeeper(earthBadgeDoorkeeper);
boolean check = boulderBadgeDoorkeeper.check(player);
if (check) {
System.out.println("挑戰者 " + player.getName() + " 通過冠軍之路");
} else {
System.out.println("請繼續挑戰各地的道館,直到獲得八個徽章吧");
}
}
}
徽章物件、使用者物件:Badge
、User
class Badge {
/** @param {string} name */
constructor(name) {
this.name = name;
}
show() {
return this.name;
}
}
class Player {
/** @param {string} name */
constructor(name) {
this.name = name;
/** @type {Map<string, Badge>} */
this.badgeBox = new Map();
}
getName() {
return this.name;
}
/** @param {Badge} badge */
addNewBadge(badge) {
this.badgeBox.set(badge.show(), badge);
}
/** @param {string} badgeName */
showBadge(badgeName) {
if (this.badgeBox.has(badgeName)) {
return this.badgeBox.get(badgeName);
} else {
return null;
}
}
}
步驟的虛擬層親代:Doorkeeper
/** @abstract */
class Doorkeeper {
/** @param {string} name */
constructor(name) {
this.name = name;
/** @type {Doorkeeper} */
this.nextDoorkeeper = null;
}
/** @param {Doorkeeper} doorkeeper */
setNextDoorkeeper(doorkeeper) {
this.nextDoorkeeper = doorkeeper;
}
/**
* @abstract
* @param {Player} player
* @returns {boolean}
*/
check(player) { return; }
}
步驟子代:BoulderBadgeDoorkeeper
、CascadeBadgeDoorkeeper
、ThunderBadgeDoorkeeper
、RainbowBadgeDoorkeeper
、SoulBadgeDoorkeeper
、MarshBadgeDoorkeeper
、VolcanoBadgeDoorkeeper
、EarthBadgeDoorkeeper
(Chain of Responsibility 物件)
class BoulderBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("灰色徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有灰色徽章");
const badge = player.showBadge("Boulder");
if (badge == null) {
console.log("你未持有灰色徽章,不能通過此門\n");
return false;
}
console.log("你持有灰色徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class CascadeBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("藍色徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有藍色徽章");
const badge = player.showBadge("Cascade");
if (badge == null) {
console.log("你未持有藍色徽章,不能通過此門\n");
return false;
}
console.log("你持有藍色徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class ThunderBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("橙色徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有橙色徽章");
const badge = player.showBadge("Thunder");
if (badge == null) {
console.log("你未持有橙色徽章,不能通過此門\n");
return false;
}
console.log("你持有橙色徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class RainbowBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("彩虹徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有彩虹徽章");
const badge = player.showBadge("Rainbow");
if (badge == null) {
console.log("你未持有彩虹徽章,不能通過此門\n");
return false;
}
console.log("你持有彩虹徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class SoulBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("粉紅徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有粉紅徽章");
const badge = player.showBadge("Soul");
if (badge == null) {
console.log("你未持有粉紅徽章,不能通過此門\n");
return false;
}
console.log("你持有粉紅徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class MarshBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("金色徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有金色徽章");
const badge = player.showBadge("Marsh");
if (badge == null) {
console.log("你未持有金色徽章,不能通過此門\n");
return false;
}
console.log("你持有金色徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class VolcanoBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("深紅徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有深紅徽章");
const badge = player.showBadge("Volcano");
if (badge == null) {
console.log("你未持有深紅徽章,不能通過此門\n");
return false;
}
console.log("你持有深紅徽章,請通過此門\n");
return this.nextDoorkeeper.check(player);
}
}
class EarthBadgeDoorkeeper extends Doorkeeper {
constructor() {
super("綠色徽章檢查者");
}
/**
* @override
* @param {Player} player
* @returns {boolean}
*/
check(player) {
console.log("我是 " + this.name + ",負責檢查是否有綠色徽章");
const badge = player.showBadge("Earth");
if (badge == null) {
console.log("你未持有綠色徽章,不能通過此門\n");
return false;
}
console.log("你持有綠色徽章,請通過此門\n");
return true;
}
}
測試,挑戰者小智嘗試通過冠軍之路的徽章檢查:victoryRoadChainOfResponsibilitySample
const victoryRoadChainOfResponsibilitySample = () => {
const player = new Player("小智");
player.addNewBadge(new Badge("Boulder"));
player.addNewBadge(new Badge("Cascade"));
player.addNewBadge(new Badge("Thunder"));
player.addNewBadge(new Badge("Rainbow"));
player.addNewBadge(new Badge("Soul"));
player.addNewBadge(new Badge("Marsh"));
player.addNewBadge(new Badge("Volcano"));
player.addNewBadge(new Badge("Earth"));
const boulderBadgeDoorkeeper = new BoulderBadgeDoorkeeper();
const cascadeBadgeDoorkeeper = new CascadeBadgeDoorkeeper();
const thunderBadgeDoorkeeper = new ThunderBadgeDoorkeeper();
const rainbowBadgeDoorkeeper = new RainbowBadgeDoorkeeper();
const soulBadgeDoorkeeper = new SoulBadgeDoorkeeper();
const marshBadgeDoorkeeper = new MarshBadgeDoorkeeper();
const volcanoBadgeDoorkeeper = new VolcanoBadgeDoorkeeper();
const earthBadgeDoorkeeper = new EarthBadgeDoorkeeper();
boulderBadgeDoorkeeper.setNextDoorkeeper(cascadeBadgeDoorkeeper);
cascadeBadgeDoorkeeper.setNextDoorkeeper(thunderBadgeDoorkeeper);
thunderBadgeDoorkeeper.setNextDoorkeeper(rainbowBadgeDoorkeeper);
rainbowBadgeDoorkeeper.setNextDoorkeeper(soulBadgeDoorkeeper);
soulBadgeDoorkeeper.setNextDoorkeeper(marshBadgeDoorkeeper);
marshBadgeDoorkeeper.setNextDoorkeeper(volcanoBadgeDoorkeeper);
volcanoBadgeDoorkeeper.setNextDoorkeeper(earthBadgeDoorkeeper);
const check = boulderBadgeDoorkeeper.check(player);
if (check) {
console.log("挑戰者 " + player.getName() + " 通過冠軍之路");
} else {
console.log("請繼續挑戰各地的道館,直到獲得八個徽章吧");
}
}
victoryRoadChainOfResponsibilitySample();
光看名稱,很難想像 Chain of Responsibility 模式的功用,當理解需求是轉換需要多步驟的行為時,頓時豁然開朗。同時,理解該模式是針對特殊情況下的解,難以用於其他情境下。
明天將介紹 Behavioural patterns 的第二個模式:Command 模式。